﻿module SourcesTests

open System
open System.IO
open Microsoft.VisualStudio.TestTools.UnitTesting
open Streams
open Sources

[<TestClass>]
type public SourcesTests() = class

   [<TestMethod>]
   member public self.IsBoxed_RecognizesQuotes() =
      let text = Some("\"boxed\"")
      let actual = IsBoxed(text)

      Assert.IsTrue(actual)


   [<TestMethod>]
   member public self.IsBoxed_RecognizesTicks() =
      let text = Some("`boxed`")
      let actual = IsBoxed(text)

      Assert.IsTrue(actual)


   [<TestMethod>]
   member public self.IsBoxed_FailsOnAnythingElse() =
      let text = Some("not boxed")
      let actual = IsBoxed(text)

      Assert.IsFalse(actual)


   [<TestMethod>]
   member public self.SourceReader_SetsLocationProperly() =
      use stream = CreateStream("abc")
      use reader = CreateReader(stream)

      reader.Move() 
      
      let location = reader.GetLocation() 

      reader.Move()

      let actual = reader.Read() 

      Assert.AreEqual('c', actual)
      Assert.AreEqual(4, reader.GetLocation().Index)
            
      reader.SetLocation(location) 

      let actual = reader.Read() 

      Assert.AreEqual('b', actual)
      Assert.AreEqual(3, reader.GetLocation().Index)
      

   [<TestMethod>]
   member public self.SourceReader_IncrementsIndexProperly() =
      use stream = CreateStream("123")
      use reader = CreateReader(stream)

      reader.Move()
      reader.Move()
            
      Assert.AreEqual(3, reader.GetLocation().Index)


   [<TestMethod>]
   member public self.SourceReader_IncrementsLineNumbersProperly() =
      use stream = CreateStream("1\n2\n3")
      use reader = CreateReader(stream)

      reader.Move()
      reader.Move()
      reader.Move()
      reader.Move()
      
      Assert.AreEqual(3, reader.GetLocation().Line)

   [<TestMethod>]
   member public self.SourceReader_IncrementsColumnNumbersProperly() =
      use stream = CreateStream("1\n2\n3")
      use reader = CreateReader(stream)

      reader.Move()
      reader.Move()
      reader.Move()

      Assert.AreEqual(2, reader.GetLocation().Column)

      reader.Move()
      
      Assert.AreEqual(1, reader.GetLocation().Column)


   [<TestMethod>]
   member public self.SkipComments_SkipsAllComments() =
      use stream = CreateStream("{comment #1 {comment #2}}TEST")
      use reader = CreateReader(stream)

      SkipComments(reader) 

      let actual = reader.Read()

      Assert.AreEqual('T', actual)


   [<TestMethod>]
   member public self.SkipIrrelevant_SkipsAllWhitespaceCharacters() =
      use stream = CreateStream(" \t\r\nTEST")
      use reader = CreateReader(stream)
      
      SkipIrrelevant(reader)

      let actual = reader.Read()

      Assert.AreEqual('T', actual)


   [<TestMethod>]
   member public self.SkipIrrelevant_SkipsAllComments() =
      use stream = CreateStream(" {comment #1} {comment #2}TEST")
      use reader = CreateReader(stream)

      SkipIrrelevant(reader)

      let actual = reader.Read()

      Assert.AreEqual('T', actual)

   [<TestMethod>]
   member public self.SkipIrrelevant_SkipsNestedComments() =
      use stream = CreateStream(" {comment #1{comment #2}}TEST")
      use reader = CreateReader(stream)

      SkipIrrelevant(reader)

      let actual = reader.Read()

      Assert.AreEqual('T', actual)


   [<TestMethod>]
   member public self.ReadWord_ReadsUntilWhitespace() =
      use stream = CreateStream("TEST ")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader).Value

      Assert.AreEqual("TEST", actual)


   [<TestMethod>]
   member public self.ReadWord_ReadsUntilCRLF() =
      use stream = CreateStream("TEST\r\n")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader).Value

      Assert.AreEqual("TEST", actual)


   [<TestMethod>]
   member public self.ReadWord_ReadsUntilComment() =
      use stream = CreateStream("TEST{")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader).Value

      Assert.AreEqual("TEST", actual)


   [<TestMethod>]
   member public self.ReadWord_ReadsUntilQuote() =
      use stream = CreateStream("TEST\"")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader).Value

      Assert.AreEqual("TEST", actual)


   [<TestMethod>]
   member public self.ReadWord_ReadsUntilTick() =
      use stream = CreateStream("TEST`")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader).Value

      Assert.AreEqual("TEST", actual)


   [<TestMethod>]
   member public self.ReadWord_ReadsUntilPeriod() =
      use stream = CreateStream("TEST.")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader).Value

      Assert.AreEqual("TEST", actual)


   [<TestMethod>]
   member public self.ReadWord_ReturnsNadaIfStartedAtAnIrrelevantCharacter() =
      use stream = CreateStream(" TEST")
      use reader = CreateReader(stream)

      let actual = ReadWord(reader)

      Assert.IsTrue(actual.IsNone)


   [<TestMethod>]
   member public self.ReadSequence_ReadsUntilEndQuote() =
      use stream = CreateStream("\"THIS IS A TEST\" ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '"', '"').Value

      Assert.AreEqual("\"THIS IS A TEST\"", actual)


   [<TestMethod>]
   member public self.ReadSequence_ReturnsNadaIfStartedAtAnIrrelevantCharacter() =
      use stream = CreateStream(" \"TEST\" ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '"', '"')

      Assert.IsTrue(actual.IsNone)


   [<TestMethod>]
   member public self.ReadSequence_ReadsTicksWithinQuotes() =
      use stream = CreateStream("\"T`E`S`T\" ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '"', '"').Value

      Assert.AreEqual("\"T`E`S`T\"", actual)


   [<TestMethod>]
   member public self.ReadSequence_ReadsPeriodsWithinQuotes() =
      use stream = CreateStream("\"T.E.S.T\" ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '"', '"').Value

      Assert.AreEqual("\"T.E.S.T\"", actual)
      

   [<TestMethod>]
   member public self.ReadSequence_ReadsCommentsWithinQuotes() =
      use stream = CreateStream("\"T{ES}T\" ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '"', '"').Value

      Assert.AreEqual("\"T{ES}T\"", actual)


   [<TestMethod>]
   member public self.ReadSequence_ReadsUntilEndTick() =
      use stream = CreateStream("`THIS IS A TEST` ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '`', '`').Value

      Assert.AreEqual("`THIS IS A TEST`", actual)


   [<TestMethod>]
   member public self.ReadSequence_ReadsQuotesWithinTicks() =
      use stream = CreateStream("`T\"E\"S\"T` ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '`', '`').Value

      Assert.AreEqual("`T\"E\"S\"T`", actual)
      

   [<TestMethod>]
   member public self.ReadSequence_ReadsPeriodsWithinTicks() =
      use stream = CreateStream("`T.E.S.T` ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '`', '`').Value

      Assert.AreEqual("`T.E.S.T`", actual)
      

   [<TestMethod>]
   member public self.ReadSequence_ReadsCommentsWithinTicks() =
      use stream = CreateStream("`T{ES}T` ")
      use reader = CreateReader(stream)

      let actual = ReadSequence(reader, '`', '`').Value

      Assert.AreEqual("`T{ES}T`", actual)
        

   end